#include "YGScene.h"

#include "YGRoot.h"
#include "YGSources.h"
#include "YGSprite.h"

namespace YoghurtGum
{

	Scene::Scene()
	{
		m_ObjectFirst = NULL;
		m_ObjectCurrent = NULL;
		m_ObjectTotal = 0;
	}

	void Scene::AddObject(Entity* a_New)
	{
		Box<Entity>* add = new Box<Entity>;

		add->data = a_New;
		add->next = NULL;

		if (m_ObjectTotal == 0)
		{
			m_ObjectFirst       = add;
			m_ObjectCurrent     = add;
		}
		else
		{
			m_ObjectCurrent->next   = add;
			m_ObjectCurrent         = add;
		}

		m_ObjectTotal++;
	}

	void Scene::DeleteObject(Entity* a_Delete)
	{
		Box<Entity>* previous = NULL;
		Box<Entity>* current = m_ObjectFirst;

		for (int i = 0; i < m_ObjectTotal; ++i)
		{
			if (current->data == a_Delete)
			{
				if (previous) 
				{ 
					// last in the list
					if (current->next == NULL)
					{
						previous->next = NULL;
						m_ObjectCurrent = previous;
						delete current;
					}

					// somewhere in the list
					else
					{
						previous->next = current->next; 
						delete current;
					}

					m_ObjectTotal--;
					break;
				}

				// first in the list
				else
				{
					m_ObjectFirst = current->next;
					delete current;
					m_ObjectTotal--;
					break;
				}
			}

			previous = current;
			current = current->next;
		}
	}

	void Scene::Update()
	{
		for (Box<Entity>* current = m_ObjectFirst; current; current = current->next)
		{
			current->data->Update();
		}
	}

	Entity* Scene::CheckCollision(Entity* a_Entity)
	{
		// TODO: Make collision checking faster

		Vec2 collide_min = Vec2 (
			a_Entity->m_X, 
			a_Entity->m_Y
		);
		Vec2 collide_max = Vec2 (
			a_Entity->m_X + a_Entity->m_Sprite->GetWidth(), 
			a_Entity->m_Y + a_Entity->m_Sprite->GetHeight()
		);

		for (Box<Entity>* current = m_ObjectFirst; current != NULL; current = current->next)
		{
			if (current->data == a_Entity) { continue; }

			if (
				current->data->Collide(collide_min) || 
				current->data->Collide(collide_max)
			)
			{
				return current->data;
			}
		}

		return NULL;
	}

	void Scene::Render()
	{
		// TODO: Get rid of sorting

		Box<Entity>* current;

		// let's just do a bubble sort for now
		Box<Entity>* sorted_first;
		Box<Entity>* sorted_current;
		Box<Entity>* sorted_previous;
		int filled = 0;
		for (current = m_ObjectFirst; current != NULL; current = current->next)
		{
			if (filled == 0)
			{
				sorted_first = new Box<Entity>;
				sorted_first->data = current->data;
				sorted_first->next = NULL;

				sorted_previous = sorted_first;
			}
			else
			{
				sorted_current = sorted_first;

				float depth1 = current->data->GetDepth();

				if (depth1 < sorted_first->data->GetDepth())
				{
					// 0 -> 1
					// -1 -> 0 -> 1

					Box<Entity>* swap = new Box<Entity>;
					swap->data = sorted_first->data;
					swap->next = sorted_first->next;

					sorted_first->data = current->data;
					sorted_first->next = swap;
				}
				else
				{
					for (int i = 0; i < filled; i++)
					{
						float depth2 = sorted_current->data->GetDepth();

						if (depth1 >= depth2)
						{
							// 0 -> 1
							// 0 -> 2 -> 1

							Box<Entity>* add = new Box<Entity>;
							add->data = current->data;
							add->next = sorted_current->next;
							sorted_current->next = add;

							break;
						}

						sorted_previous = sorted_current;
						sorted_current = sorted_current->next;
					}
				}
			}
			
			filled++;
		}	

		for (current = sorted_first; current != NULL; current = current->next)
		{
			current->data->Render();
			current->data->PostRender();
		}
	}

	Scene* Scene::Get()
	{
		return Root::GetSingleton().GetScene();
	}

}; // namespace YoghurtGum